/*
 *   This File is Part of CuteOgre Game Engine
 *
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *	Copyright 2010 Alexandre Pires ( c.alexandre.pires@gmail.com )
 *  Created on: 2010/08/22
 */

#include "StateManager.h"
#include "GameEngine.h"
#include "LogManager.h"
#include "VideoPlayerState.h"
#include "IdleState.h"
#include "MainMenuState.h"

template<> StateManager* Singleton<StateManager>::ms_Singleton = 0;

void StateManager::run () {

	while ( !mShutdown ) {
		InputManager::getSingletonPtr ()->updateEvents ();
		updateState ();
	}

}

void StateManager::changeState ( const QString& rStateName,
		const QString& rScript ) {

	AbstractGameState* next_state = mAvailableStates[rStateName];

	if ( !next_state )
		return;

	while ( !mStates.empty () ) {

		AbstractGameState* curr_state = mStates.back ();
		curr_state->cleanup ();

		mStates.pop_back ();
	}

	mStates.push_back ( next_state );
	next_state->init ( rScript );
}

void StateManager::pushState ( const QString& rStateName,
		const QString& rScript ) {

	AbstractGameState* next_state = mAvailableStates[rStateName];

	if ( !next_state )
		return;

	if ( !mStates.empty () ) {

		AbstractGameState* curr_state = mStates.back ();
		curr_state->pause ();
	}

	mStates.push_back ( next_state );
	next_state->init ( rScript );
}

void StateManager::popState () {

	if ( !mStates.empty () ) {

		AbstractGameState* state = mStates.back ();
		state->cleanup ();

		mStates.pop_back ();
	}

	if ( !mStates.empty () ) {

		AbstractGameState* old_state = mStates.back ();
		old_state->resume ();

	} else {
		changeState ( "Idle" );
	}
}

void StateManager::updateState () {

	if ( mStates.empty () ) {
		changeState ( "Idle" );
		return;
	}

	AbstractGameState* curr_state = mStates.back ();
	curr_state->update ();
}

void StateManager::injectKeyPressed ( int rKey, unsigned int rText ) {

	if ( mStates.empty () ) {
		return;
	}

	AbstractGameState* state = mStates.back ();
	state->injectKeyPressed ( rKey, rText );
}

void StateManager::injectKeyReleased ( int rKey ) {

	if ( mStates.empty () ) {
		return;
	}

	AbstractGameState* state = mStates.back ();
	state->injectKeyReleased ( rKey );
}

void StateManager::injectMouseMoved ( int rX, int rY, int rZ ) {

	if ( mStates.empty () ) {
		return;
	}

	AbstractGameState* state = mStates.back ();
	state->injectMouseMoved ( rX, rY, rZ );
}

void StateManager::injectMousePressed ( int rX, int rY, int rMouseButton ) {

	if ( mStates.empty () ) {
		return;
	}

	AbstractGameState* state = mStates.back ();
	state->injectMousePressed ( rX, rY, rMouseButton );
}

void StateManager::injectMouseReleased ( int rX, int rY, int rMouseButton ) {

	if ( mStates.empty () ) {
		return;
	}

	AbstractGameState* state = mStates.back ();
	state->injectMouseReleased ( rX, rY, rMouseButton );
}

void StateManager::init () {

	if ( !mShutdown )
		return;

	LogManager::message ( "StateManager::Starting up" );

	mAvailableStates.insert ( "VideoPlayer", new VideoPlayerState ( this ) );
	mAvailableStates.insert ( "Idle", new IdleState ( this ) );
	mAvailableStates.insert ( "MainMenu", new MainMenuState ( this ) );

	ScriptManager::setup ( &mEngine );
	ScriptManager::load ( "init.js", &mEngine );

	mShutdown = false;
}

void StateManager::shutdown () {

	if ( mShutdown )
		return;

	LogManager::message ( "StateManager::Shutting down" );

	mShutdown = true;

	while ( !mStates.empty () ) {

		AbstractGameState* curr_state = mStates.back ();
		curr_state->cleanup ();

		mStates.pop_back ();
	}

	mAvailableStates.clear ();
}
